#include "stdafx.h"
#include "ProjectCodeTypeTree.h"


BOOL CProjectCodeTypeTree::Element(EnvDTE::CodeElement * pElement)
{
	EnvDTE::vsCMElement eKind;
	if (SUCCEEDED(pElement->get_Kind(&eKind)))
	{
		switch (eKind)
		{
		case EnvDTE::vsCMElementClass:
		case EnvDTE::vsCMElementStruct:
		case EnvDTE::vsCMElementFunction:
		case EnvDTE::vsCMElementInterface:
		case EnvDTE::vsCMElementNamespace:
			AddElement(pElement);
			break;
		
		//	break;
		//default: do nothing
		}
	}
	return TRUE;
}

void CProjectCodeTypeTree::AddElement(EnvDTE::CodeElement * pElement)
{
	CAtlList<CodeTreeItem> lst;

	Walk(pElement, lst);

	Form(lst, lst.GetHeadPosition(), *this);
}

void CProjectCodeTypeTree::Walk(EnvDTE::CodeElement * pElement, CAtlList<CodeTreeItem> & rList)
{
	CComBSTR bstrName;
	CodeTreeItem st;

	if (SUCCEEDED(pElement->get_Kind(&st.eKind)) &&
		SUCCEEDED(pElement->get_Name(&bstrName)))
	{
		st.Name = bstrName;

		IDispatchPtr spDispatch;
		switch (st.eKind)
		{
		case EnvDTE::vsCMElementClass:
			{
				EnvDTE::CodeClassPtr spCodeClass(pElement);
				if (spCodeClass)
					spCodeClass->get_Parent(&spDispatch);
			}
			break;
		case EnvDTE::vsCMElementStruct:
			{
				EnvDTE::CodeStructPtr spCodeStruct(pElement);
				if (spCodeStruct)
					spCodeStruct->get_Parent(&spDispatch);
			}
			break;
		case EnvDTE::vsCMElementInterface:
			{
				EnvDTE::CodeInterfacePtr spCodeInterface(pElement);
				if (spCodeInterface)
				{
					spCodeInterface->get_Parent(&spDispatch);
					st.Abstract = TRUE;
				}
			}
			break;
		case EnvDTE::vsCMElementFunction:
			{
				EnvDTE::CodeFunctionPtr spCodeFunction(pElement);
				st.ElementData.eFunctionKind = EnvDTE::vsCMFunctionOther;
				if ((spCodeFunction) &&
					SUCCEEDED(spCodeFunction->get_Parent(&spDispatch)) &&
					SUCCEEDED(spCodeFunction->get_FunctionKind(&st.ElementData.eFunctionKind)))
				{
					st.Abstract = (st.ElementData.eFunctionKind & EnvDTE::vsCMFunctionPure) == EnvDTE::vsCMFunctionPure;
				}
			}
			break;
		case EnvDTE::vsCMElementNamespace:
			{
				EnvDTE::CodeNamespacePtr spCodeNamespace(pElement);
				if (spCodeNamespace)
					spCodeNamespace->get_Parent(&spDispatch);

				if (-1 != st.Name.Find(_T('\''))) //unnamed namespace
					st.Name.Empty();
			}
		}

		if (st.Name.GetLength()) //ignore global namespace
		{ 
			rList.AddHead(st);
		}

		EnvDTE::CodeElementPtr spParent;
		if (spParent = spDispatch)
		{
			Walk(spParent, rList);
		}
	}
}

void CProjectCodeTypeTree::Form(const CAtlList<CodeTreeItem> & rList, POSITION pos, CElementTree<CodeTreeItem> & Node)
{
	if (pos)
	{
		const CodeTreeItem & rItem = rList.GetNext(pos);
		POSITION posItem = Node.Find(rItem);
		if (posItem == NULL)
		{
			posItem	= Node.AddTail(rItem);	
		}

		if ((rItem.Abstract) && (rItem.eKind == EnvDTE::vsCMElementFunction))
		{
			CodeTreeItem & rNodeValue = Node.GetValue();
			if ((rNodeValue.eKind == EnvDTE::vsCMElementClass) || (rNodeValue.eKind == EnvDTE::vsCMElementStruct))
				rNodeValue.Abstract = TRUE;
		} else
		{
			Form(rList, pos, Node.GetAt(posItem));
		}
	}
}
